home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / lists / mint / l_0799 / 502 < prev    next >
Encoding:
Internet Message Format  |  1994-08-27  |  55.0 KB

  1. From: Juergen Lock <nox@jelal.north.de>
  2. From: Juergen Lock <nox@jelal.north.de>
  3. Subject: try this out...
  4. Date: Sat, 18 Sep 93 18:55:54 CES
  5. From: Juergen Lock <nox@jelal.north.de>
  6. Message-Id: <9309181656.AA00236@jelal.north.de>
  7.  
  8. hi!
  9.  
  10.  this started as an idea last week, and now...
  11.  
  12.  (please don't pass this around until i know its reasonably stable.
  13. works for me, i'm using it right now but as usual that doesn't say
  14. much...  i would also like some comment from Eric because it contains
  15. parts which are his code.  thanx...)
  16.  
  17. #    This is a shell archive.
  18. #    Remove everything above and including the cut line.
  19. #    Then run the rest of the file through sh.
  20. #----cut here-----cut here-----cut here-----cut here----#
  21. #!/bin/sh
  22. # shar:    Shell Archiver
  23. #    Run the following text with /bin/sh to create:
  24. #    README
  25. #    vcon.c
  26. #    vtdev.c
  27. #    vcon.h
  28. #    vtdev.h
  29. #    Makefile
  30. # This archive created: 18-September-1993 18:13:06 CES
  31. # By:    nox@jelal.north.de (Juergen Lock)
  32. cat << \SHAR_EOF > README
  33. From: Juergen Lock <nox@jelal.north.de>
  34.  
  35. here is something you've all been waiting for... virtual terminals
  36. for MiNT :-)  now you can...
  37.  
  38.  use up to 10 shells/whatever without magnifying glasses or 19" screens
  39.  run GEM on the console, top on vt01 and gdb' a GEM program from vt02...
  40.  send MiNTs debug output to another terminal than the debugged program
  41.  when some stupid program hangs and MiNT is still alive just switch to
  42. another terminal and send the thing a signal. (ever heared of vp/ix?
  43. oops, wrong CPU...)
  44.  temporarily suspend GEM while you need your cycles for something more
  45. important than polling the mouse ;)  i.e. just send SIGSTOP and SIGCONT
  46. later. (now if MiNT only had swapping...)
  47.  show people that its not MiNT that is slow, only GEM :-)  also the
  48. screen writing code in vtdev.c is mostly based on MiNTs fasttext.c
  49. (including hardware scrolling for all terminals except the console)
  50. so i guess output is faster than any GEM window writing could ever get.
  51.  
  52.  how to use:
  53.  
  54.  this should run ok on any machine where MiNTs /dev/fasttext worked
  55. (worked because you won't need it anymore then) and where
  56. Setscreen (-1, base, -1) allows setting the displayed screen
  57. independent of the one GEM (or VDI actually) writes to.  if it doesn't
  58. work for you tell me, or better yet just fix it and send diffs. :-)
  59.  
  60.  with init simply put something like this into your rc.local:
  61.  
  62. --------cut------
  63. if [ -f /usr/etc/vcon ]; then
  64.     echo "starting virtual consoles"
  65.     vcon
  66.     mv /dev/console /dev/con00
  67.     mv /dev/vt00 /dev/console
  68.     rm /etc/ttytab
  69.     ln /etc/ttytab.vt /etc/ttytab
  70. else
  71.     rm /etc/ttytab
  72.     ln /etc/ttytab.con /etc/ttytab
  73. fi
  74. -------------
  75.  
  76.  (the mv.s are for programs that open /dev/console so they get the
  77. new one... writing to the old one should be no problem, but reading is.)
  78.  
  79.  ttytab.vt has entries for console and vt01..09 (of course not all of
  80. them need be `on' :-), ttytab.con only has the original console.  and
  81. remember GEM can only run on console...
  82.  
  83.  without init put something like this in mint.cnf (and then set CON to
  84. the new console).  of course without init you'll have to do its job
  85. yourself, i.e. put gettys or shells etc. on the new terminals `by hand'.
  86.  
  87.  you can also add this to termcap:
  88.  
  89. stv52|MiNT virtual console:\
  90.     :ti=\Ev\Ee\Ez_:am:te=\Ev\Et@\Ee\Ez_:\
  91.     :al=\EL:bs:cd=\EJ:ce=\EK:cl=\EE:cm=\EY%+ %+ :co#80:\
  92.     :dl=\EM:do=\EB:ho=\EH:\
  93.     :li#25:se=\Eq:so=\Ep:up=\EA:nd=\EC:\
  94.     :rs=\Ez_\Eb@\EcA:\
  95.     :ue=\EzH:us=\EyH:md=\E(:me=\E)\Eq:\
  96.     :ms:pt:\
  97.     :sr=2*\EI:\
  98.     :sf=2*^J:\
  99.     :kl=#K:kr=#M:ku=#H:kd=#P:\
  100.     :kI=#R:kh=#G:kH=#O:kP=#I:kN=#Q:\
  101.     :k0=#D:k1=#;:k2=#<:k3=#=:\
  102.     :k4=#>:k5=#?:k6=#@:k7=#A:k8=#B:k9=#C:\
  103.     :s0=#]:s1=#T:s2=#U:s3=#V:\
  104.     :s4=#W:s5=#X:s6=#Y:s7=#Z:s8=#[:s9=#\\:\
  105.     :vi=\Ef:ve=\Et@\Ee:vs=\Et :\
  106.     :cQ=\Et@:cV=\Et :
  107.  
  108. (and add a new console type to gettytab that sets tt i.e. TERM =stv52),
  109. then less etc know how to underline text wich i also have added.
  110. btw the k.. and s.. with # are scancodes for elvis, others might want
  111. escape sequences...
  112.  
  113.  oh and to switch between terminals just hit alt-fkey... f10 is the
  114. console.  when it `bing's at you that means the terminal has no screen
  115. memory because no process has it open... with init you can turn it on in
  116. ttytab and send init SIGHUP.  and when it `bing's at you while you type
  117. that means the terminals `keyboard queue' is full... to empty it hit
  118. alt-undo.  (if its empty alt-undo gets passed thru, so programs can
  119. still use it.)
  120.  
  121.  ok, happy testing...
  122.     Juergen
  123. SHAR_EOF
  124. cat << \SHAR_EOF > vcon.c
  125. /*
  126.  * virtual terminals for MiNT, 1st try
  127.  *
  128.  * vt01..9 are fast hardware-scrolling text-terminals, vt00 is the
  129.  * original console and can still be used for GEM. (i hope :)
  130.  * to change terminals hit alt-function key (f1 == vt01... f10 == vt00),
  131.  * alt-undo kills a terminals key buffer. (useful when your auto-repeat
  132.  * is faster than a program processes input, etc)
  133.  *
  134.  * how it works:  each open vt.. device has a screen buffer and input pipe.
  135.  * keyboard input is read and scanned for control and alt-f keys by a
  136.  * daemon (in main()) that changes screens and sends input and signals to
  137.  * the correct processes.
  138.  * vt00 uses the original screen memory, vt01..9 share one bigger screen
  139.  * for display and store the other screens contents in line buffers
  140.  * so they can be `hardware-scrolled' without taking extra memory.
  141.  * (just move pointers around.. line offsets actually)  closed `stored'
  142.  * terminals don't take up screen memory.
  143.  *
  144.  * send bugs & comments to:  Juergen Lock <nox@jelal.north.de>
  145.  */
  146.  
  147. #include <osbind.h>
  148. #include <sysvars.h>
  149. #undef flock
  150. #undef    _sysbase
  151. #define    _sysbase (* ((OSHEADER **) 0x4f2))
  152. #include <mintbind.h>
  153. #include <setjmp.h>
  154. #include <support.h>
  155. #include <signal.h>
  156. #include <unistd.h>
  157. #include <stdlib.h>
  158. #include <stdio.h>
  159. #include <string.h>
  160. #include "vcon.h"
  161. #include "vtdev.h"
  162.  
  163. /* kernel information */
  164. struct kerinfo *kernel;
  165.  
  166. struct dev_descr devinfo[] = {
  167.     &vcon_device, 0, O_TTY, ttys+0, 0L, 0L, 0L, 0L,    /* vt00 (console) */
  168.     &vcon_device, 1, O_TTY, ttys+1, 0L, 0L, 0L, 0L,    /* vt01 */
  169.     &vcon_device, 2, O_TTY, ttys+2, 0L, 0L, 0L, 0L,    /* vt02 */
  170.     &vcon_device, 3, O_TTY, ttys+3, 0L, 0L, 0L, 0L,    /* vt03 */
  171.     &vcon_device, 4, O_TTY, ttys+4, 0L, 0L, 0L, 0L,    /* vt04 */
  172.     &vcon_device, 5, O_TTY, ttys+5, 0L, 0L, 0L, 0L,    /* vt05 */
  173.     &vcon_device, 6, O_TTY, ttys+6, 0L, 0L, 0L, 0L,    /* vt06 */
  174.     &vcon_device, 7, O_TTY, ttys+7, 0L, 0L, 0L, 0L,    /* vt07 */
  175.     &vcon_device, 8, O_TTY, ttys+8, 0L, 0L, 0L, 0L,    /* vt08 */
  176.     &vcon_device, 9, O_TTY, ttys+9, 0L, 0L, 0L, 0L    /* vt09 */
  177. };
  178.  
  179. #define MAX_VT ((sizeof devinfo)/sizeof (struct dev_descr))
  180.  
  181. struct tty ttys[MAX_VT];
  182.  
  183. struct sgttyb con;
  184. int conflags;
  185. short hardscroll = -1;
  186. struct tchars con_tc, tc0;
  187. struct ltchars con_ltc, ltc0;
  188.  
  189. int pfd[MAX_VT], cfd, vcurrent, pgrp;
  190. short leaving;
  191.  
  192. static int xcurrent;
  193.  
  194. void xflash();
  195.  
  196. long xsetcurrent()
  197. {
  198.     return setcurrent (xcurrent);
  199. }
  200.  
  201. void xwakeselect()
  202. {
  203.     WAKESELECT(ttys[vcurrent].rsel);
  204. }
  205.  
  206. void con_raw()
  207. {
  208.     Fcntl(0, &con, TIOCGETP);
  209.     Fcntl(0, &con_tc, TIOCGETC);
  210.     Fcntl(0, &con_ltc, TIOCGLTC);
  211.     conflags = con.sg_flags;
  212.     con.sg_flags &= ~(CBREAK|ECHO|TOSTOP);
  213.     Fcntl(0, &con, TIOCSETN);
  214.     Fcntl(0, &tc0, TIOCSETC);
  215.     Fcntl(0, <c0, TIOCSLTC);
  216. }
  217.  
  218. void con_sane()
  219. {
  220.     if (cfd) {
  221.         /* try to uninstall gracefully... */
  222.         int i, opencnt = 0;
  223.         char *vt00name=ttyname(cfd), *oldcname=ttyname(0), *s;
  224.         long vpgrp;
  225.  
  226.         /* /dev/vt00 might be renamed /dev/console... */
  227.         if (vt00name && (s = strrchr (vt00name, '/')) &&
  228.             !strcmp (s, "/console"))
  229.             rename (vt00name, "u:/dev/vt00");
  230.         /* move original console device in place */
  231.         if (oldcname && (s = strrchr (oldcname, '/')) &&
  232.             strcmp (s, "/console"))
  233.             rename (oldcname, "u:/dev/console");
  234.  
  235.         /* tell processes their tty is going away */
  236.         leaving = 1;
  237.         for (i = 0; i < MAX_VT; ++i) {
  238.             if (ttys[i].use_cnt > !i) {
  239.                 ++opencnt;
  240.                 if ((vpgrp = ttys[vcurrent].pgrp))
  241.                     killpg(vpgrp, SIGHUP);
  242.             }
  243.         }
  244.         /* wait until all the devices are closed... */
  245.         while (opencnt) {
  246.             opencnt = 0;
  247.             /* sleep(1);  (save space...) */
  248.             (void) Fselect (1000, 0l, 0l, 0l);
  249.             for (i = 0; i < MAX_VT; ++i)
  250.                 if (ttys[i].use_cnt > !i)
  251.                     ++opencnt;
  252.         }
  253.         xcurrent = 0;
  254.         Supexec (xsetcurrent);
  255.         Fclose (cfd);
  256.  
  257.         /* ..and remove them */
  258.         for (i = 0; i < MAX_VT; ++i) {
  259.             char name[] = "u:\\dev\\vt00";
  260.  
  261.             name[sizeof "u:\\dev\\vt0"-1] = i+'0';
  262.             Fdelete (name);
  263.         }
  264. #if 1
  265.         vpgrp = 0;
  266.         Fcntl(0, &vpgrp, TIOCSPGRP);
  267. #endif
  268.     }
  269.     con.sg_flags=conflags;    /* restore console  */
  270.     Fcntl(0, &con, TIOCSETN);
  271.     Fcntl(0, &con_tc, TIOCSETC);
  272.     Fcntl(0, &con_ltc, TIOCSLTC);
  273. }
  274.  
  275. /* handle fatal signals */
  276. void trap(sig)
  277. int sig;
  278. {
  279.     con_sane();
  280.     signal(sig, SIG_DFL);
  281.     /* die! */
  282.     kill(getpid(), sig);
  283. }
  284.  
  285. /* pass signal to process on the pty */
  286. void trap_int(sig)
  287. int sig;
  288. {
  289.     int vpgrp;
  290.  
  291.     /* see who is on the tty and if its a different process group... */
  292.     if (ttys[vcurrent].use_cnt && (vpgrp = ttys[vcurrent].pgrp) != pgrp) {
  293.         /* if yes, pass the signal */
  294.         signal(sig, SIG_IGN);
  295.         killpg(vpgrp, sig);
  296.         signal(sig, trap_int);
  297.     }
  298. }
  299.  
  300. static    OSHEADER *syshdr;
  301.  
  302. void getsyshd()
  303. {
  304.     syshdr = _sysbase->os_beg;
  305. }
  306.  
  307. /* get a (TOS version dependant) pointer to the current shift/alt
  308.    keyboard status
  309. */
  310. char *getpkbshift()
  311. {
  312.     /* get OS header */
  313.     (void) Supexec(getsyshd);
  314.     /* TOS 1.(0)2 or newer has it in the header */
  315.     if (syshdr->os_version > 0x100)
  316.         return syshdr->pkbshift;
  317.     else
  318.     /* TOS 1.0 */
  319.         return (char *) 0x0e1bL;
  320. }
  321.  
  322. /* on MiNT fork and vfork both block until the child does either exec or
  323.    dies.  only tfork doesn't block but it works like a subroutine call... */
  324. static jmp_buf    tforkj;
  325.  
  326. static int in_tfork(arg)
  327. int arg;
  328. {
  329.     /* wait for parent to die before we can longjmp back */
  330.     while (getppid () > 1)
  331.         (void) Fselect (1000, 0l, 0l, 0l);
  332.     longjmp (tforkj, 1);
  333.     /*NOTREACHED*/
  334. }
  335.  
  336. /* queue up characters for a terminal */
  337.  
  338. void csend (vcurrent, fd, cbuf, bufp)
  339. int vcurrent, fd;
  340. long *cbuf, *bufp;
  341. {
  342.     long bytes = (char *)bufp - (char *)cbuf;
  343.  
  344.     if (bytes) {
  345.         /* pipe full? */
  346.         if (Foutstat (fd) < bytes)
  347.             /* bing... */
  348.             Fputchar (0, 07l, 0);
  349.         else {
  350.             /* else send buffer */
  351.             Fwrite (fd, bytes, cbuf);
  352.             /* if someone select()ed this terminal wake 'em up */
  353.             if (ttys[vcurrent].rsel)
  354.                 Supexec (xwakeselect);
  355.         }
  356.     }
  357. }
  358.  
  359. /*
  360.  * main:  initialization stuff, and a daemon that handles input from
  361.  * the physical console
  362.  */
  363.  
  364. main()
  365. {
  366.     int i;
  367.     long pgrp;
  368.     char *s;
  369.     volatile char *pkbshift = getpkbshift();
  370.     long cbuf[0x80], *bufp;
  371.  
  372.     /* sanity check */
  373.     if (!(s = ttyname (0)) || (!(s = strrchr (s, '/'))) ||
  374.         strcmp (s, "/console")) {
  375.         Cconws ("Sorry this is fast not `clean' software :)  console only...\r\n");
  376.         exit (1);
  377.     }
  378.  
  379.     /* stdin RAW, catch signals...  */
  380.     pgrp = getpid(/*0*/);
  381.     Fcntl(0, &con, TIOCGETP);
  382.     Fcntl(0, &con_tc, TIOCGETC);
  383.     Fcntl(0, &con_ltc, TIOCGLTC);
  384.     conflags = con.sg_flags;
  385.     signal(SIGHUP, trap);
  386.     signal(SIGTERM, trap);
  387.     signal(SIGINT, trap_int);
  388.     signal(SIGQUIT, trap_int);
  389.     con_raw();
  390.  
  391.     for (i = 0; i < MAX_VT; ++i) {
  392.         char name[] = "u:\\pipe\\q$vt00";
  393.  
  394.         name[sizeof "u:\\pipe\\q$vt0"-1] = i+'0';
  395.         if ((pfd[i] = Fcreate (name, FA_RDONLY|FA_CHANGED)) < 0) {
  396.             con_sane();
  397.             Cconws ("Huh?  unable to create pipe...\r\n");
  398.             exit (1);
  399.         }
  400.         /* hmm.  tfork goes thru Pexec, and Pexec looks at
  401.            close-on-exec flags...
  402.         */
  403.         Fcntl (pfd[i], 0, F_SETFD);
  404.     }
  405.     for (i = 0; i < MAX_VT; ++i) {
  406.         char name[] = "u:\\dev\\vt00";
  407.  
  408.         name[sizeof "u:\\dev\\vt0"-1] = i+'0';
  409.         kernel = (struct kerinfo *)Dcntl(DEV_INSTALL, name, devinfo+i);
  410.         if (!kernel || ((long)kernel) == -32) {
  411.             con_sane();
  412.             Cconws ("Uh :(  unable to install vt device(s)!\r\n");
  413.             exit (1);
  414.         }
  415.     }
  416.  
  417.     if ((cfd = Fopen ("u:\\dev\\vt00", O_RDWR)) < 0) {
  418.         con_sane();
  419.         Cconws ("Help!!  Fopen new console device failed.\r\n");
  420.         exit (1);
  421.     }
  422.     Fcntl (cfd, 0, F_SETFD);
  423. #if 0
  424.     /* better put this in rc.local... (or mint.cnf) */
  425.     Frename (0, "u:\\dev\\console", "u:\\dev\\con00");
  426.     Frename (0, "u:\\dev\\vt00", "u:\\dev\\console");
  427. #endif
  428.  
  429.     /* hack until MiNT gets a real nonblocking fork...  one day :)
  430.     */
  431.     if (!setjmp(tforkj) && tfork (in_tfork, 0l) >= 0)
  432.         _exit (0);
  433.  
  434.     /* ok parent continues, has to close old /dev/console now... */
  435.     pgrp = setpgrp(/*pgrp, pgrp*/);
  436.     Fcntl(0, &pgrp, TIOCSPGRP);
  437.     Fcntl(0, (void *) O_NDELAY, F_SETFL);
  438.     /* hmm part 2: tfork resets signals too... */
  439.     signal(SIGHUP, trap);
  440.     signal(SIGTERM, trap);
  441.     signal(SIGINT, trap_int);
  442.     signal(SIGQUIT, trap_int);
  443.  
  444.     /* now the daemon part
  445.        poll keyboard, switch between terminals, start/stop output,
  446.        send signals, flash cursor...
  447.     */
  448.     bufp = cbuf;
  449.     for (;;) {
  450.         char name[] = "u:\\pipe\\q$vt00";
  451.         int fd = pfd[vcurrent], scan;
  452.         char cshift;
  453.         unsigned long l;
  454.  
  455.         /* empty buffer if full */
  456.         if (bufp == cbuf+sizeof cbuf) {
  457.             csend (vcurrent, fd, cbuf, bufp);
  458.             bufp = cbuf;
  459.         }
  460.         cshift = *pkbshift;
  461.         /* if nothing to read empty buffer and do a select */
  462.         if ((l=Fgetchar (0, 0)) == MiNTEOF) {
  463.             csend (vcurrent, fd, cbuf, bufp);
  464.             bufp = cbuf;
  465.             for (;;) {
  466.                 int ctimeout = 0;
  467.                 long rfd = 1;
  468.  
  469.                 if (vcurrent) {
  470.                     SCREEN *v = v0x+vcurrent-1;
  471.                     ctimeout = 500;
  472.  
  473.                     if ((CURS_FLASH|CURS_ON) ==
  474.                         (v->flags & (CURS_FLASH|CURS_ON)))
  475.                         ctimeout = v->period*20;
  476.                 }
  477.                 if (Fselect (ctimeout, &rfd, (long *)0, (long *)0)) {
  478.                     /* show cursor if flashing and off */
  479.                     if (vcurrent) {
  480.                         SCREEN *v = v0x+vcurrent-1;
  481.  
  482.                         if ((CURS_FLASH|CURS_ON) ==
  483.                             (v->flags & (CURS_FLASH|CURS_ON|CURS_FSTATE)))
  484.                             Supexec (xflash);
  485.                     }
  486.                     /* then go read whats there */
  487.                     break;
  488.                 }
  489.                 /* select timed out, flash cursor & try again */
  490.                 Supexec (xflash);
  491.             }
  492.             continue;
  493.         }
  494.         if ((cshift & ~0x10) == 8)  switch (scan=(char) (l>>16)) {
  495.             int xfd;    /* ALT-something */
  496.  
  497.             case 0x61:    /* ALT-UNDO: flush pipe if !empty */
  498.                 name[sizeof "u:\\pipe\\q$vt0"-1] = vcurrent+'0';
  499.                 if ((xfd = Fopen (name, O_RDONLY)) >= 0
  500.                     && Finstat (xfd) > 0) {
  501.                     Fcntl (xfd, (char *) 0, TIOCFLUSH);
  502.                     Fclose (xfd);
  503.                     bufp = cbuf;
  504.                     continue;
  505.                 } else if (bufp > cbuf) {
  506.                     bufp = cbuf;
  507.                     continue;
  508.                 }
  509.                 break;
  510.             case 0x3b:    /* ALT-F1: vt01 */
  511.             case 0x3c:    /* ALT-F2: vt02 */
  512.             case 0x3d:    /* .    */
  513.             case 0x3e:    /* .    */
  514.             case 0x3f:    /* .    */
  515.             case 0x40:
  516.             case 0x41:
  517.             case 0x42:
  518.             case 0x43:    /* ALT-F9:  vt09 */
  519.                 scan += 10;
  520.                 /*FALLTHRU*/
  521.             case 0x44:    /* ALT-F10: vt00 */
  522.                 if ((scan -= 0x44) < MAX_VT) {
  523.                     csend (vcurrent, fd, cbuf, bufp);
  524.                     bufp = cbuf;
  525.                     xcurrent = scan;
  526.                     if (Supexec (xsetcurrent))
  527.                         Fputchar (0, 07l, 0);
  528.                     continue;
  529.                 }
  530.             break;
  531.         } else    if ((ttys[vcurrent].state & TS_COOKED) ||
  532.                 (cshift & 0xc) == 0xc) {
  533.             char ch = (char) l;
  534.             int sig = 0;
  535.  
  536.             if (!ch)
  537.                 ;    /* do nothing */
  538.             else if (ch == ttys[vcurrent].tc.t_intrc)
  539.                 sig = SIGINT;
  540.             else if (ch == ttys[vcurrent].tc.t_quitc)
  541.                 sig = SIGQUIT;
  542.             else if (ch == ttys[vcurrent].ltc.t_suspc)
  543.                 sig = SIGTSTP;
  544.             else if (ch == ttys[vcurrent].tc.t_stopc) {
  545.                 ttys[vcurrent].state |= TS_HOLD;
  546.                 continue;
  547.             }
  548.             else if (ch == ttys[vcurrent].tc.t_startc) {
  549.                 ttys[vcurrent].state &= ~TS_HOLD;
  550.                 continue;
  551.             }
  552.             if (sig) {
  553.                 ttys[vcurrent].state &= ~TS_HOLD;
  554.                 if (!(ttys[vcurrent].sg.sg_flags & T_NOFLSH)) {
  555.                     Fcntl (fd, (char *) 0, TIOCFLUSH);
  556.                     bufp = cbuf;
  557.                 }
  558.                 killpg (ttys[vcurrent].pgrp, sig);
  559.                 continue;
  560.             }
  561.             else if (ttys[vcurrent].state & TS_HOLD) {
  562.                 continue;
  563.             }
  564.         }
  565.         *bufp++ = l;
  566.     }
  567. }
  568.  
  569. SHAR_EOF
  570. cat << \SHAR_EOF > vtdev.c
  571. /*
  572. virtual terminal devices, based on MiNTs fasttext.c, that is...
  573.  
  574. Copyright 1991,1992 Eric R. Smith.
  575. Copyright 1992,1993 Atari Corporation.
  576. All rights reserved.
  577. */
  578.  
  579. #include <stddef.h>
  580. #include <errno.h>
  581. #include <osbind.h>
  582. #include "vcon.h"
  583. #include "vtdev.h"
  584.  
  585. #ifdef __GNUC__
  586. #define INLINE inline
  587. #define ITYPE long    /* gcc's optimizer likes 32 bit integers */
  588. #else
  589. #define INLINE
  590. #define ITYPE int
  591. #endif
  592.  
  593. #define CONDEV    (2)
  594.  
  595. SCREEN *v00, v0x[N_VT-1];
  596.  
  597. static void paint P_((SCREEN *, int, char *)),
  598.      paint8c P_((SCREEN *, int, char *)),
  599.      paint816m P_((SCREEN *, int, char *));
  600.  
  601. INLINE static void curs_off P_((SCREEN *)), curs_on P_((SCREEN *));
  602. INLINE static void flash P_((SCREEN *));
  603. static void normal_putch P_((SCREEN *, int));
  604. static void escy_putch P_((SCREEN *, int));
  605. static void quote_putch P_((SCREEN *, int));
  606.  
  607. static    char *chartab[256];
  608.  
  609. static int fgmask[MAX_PLANES], bgmask[MAX_PLANES];
  610.  
  611. static long scrnsize;
  612.  
  613. short hardscroll;
  614. static char *hardbase, *oldbase;
  615.  
  616. #define base (*((char **)0x44eL))
  617. #define V_BASE(v) ((v) == v00 ? base : (v)->v.t.vbase)
  618. #define V_LINE(v, lx4) ((v) == v00 ? (base + *(long *)(rowoff+(lx4))) : \
  619.             ((v)->v.t.vbase + *(long *)((v)->v.t.rowlist+(lx4))))
  620. #define V_LINEAR_P(v) ((v) == v00 || (v)->v.t.on)
  621. #define VT_SCREEN(vt) ((vt) ? v0x+(vt)-1 : v00)
  622. #define escy1 (*((short *)0x4acL))
  623. #define V_ESCY1(v) ((v) == v00 ? escy1 : (v)->v.t.vescy1)
  624. #define V_FGMASK(v) ((v) == v00 ? fgmask : (v)->v.t.fgmask)
  625. #define V_BGMASK(v) ((v) == v00 ? bgmask : (v)->v.t.bgmask)
  626. #define _hz_200 (*((long *)0x4baL))
  627.  
  628. static Vfunc v00state;
  629. #define V_STATE(v) ((v) == v00 ? &v00state : &(v)->v.t.state)
  630.  
  631. static short hardline;
  632. static void (*vpaint) P_((SCREEN *, int, char *));
  633. static char *rowoff;
  634. static short qfd[N_VT], q_fl[N_VT];
  635.  
  636. void exchangeb P_((void *, void *, long));
  637. void init P_((void));
  638. int setcurrent P_((int));
  639. void hardware_scroll P_((SCREEN *));
  640. INLINE static char *PLACE P_((SCREEN *, int, int));
  641. INLINE static void gotoxy P_((SCREEN *, int, int));
  642. INLINE static void clrline P_((SCREEN *, int));
  643. INLINE static void clear P_((SCREEN *));
  644. INLINE static void clrchars P_((SCREEN *, int, int, int));
  645. INLINE static void clrfrom P_((SCREEN *, int, int, int, int));
  646. INLINE static void delete_line P_((SCREEN *, int));
  647. INLINE static void insert_line P_((SCREEN *, int));
  648. static void setbgcol P_((SCREEN *, int));
  649. static void setfgcol P_((SCREEN *, int));
  650. static void setcurs P_((SCREEN *, int));
  651. static void putesc P_((SCREEN *, int));
  652. static void escy1_putch P_((SCREEN *, int));
  653. #if 0
  654. INLINE static void put_ch P_((SCREEN *, int));
  655. #else
  656. INLINE static void put_ch00 P_((SCREEN *, int));
  657. INLINE static void put_ch0x P_((SCREEN *, int));
  658. #endif
  659.  
  660. /* routines for flashing the cursor for screen v */
  661. /* flash(v): invert the character currently under the cursor */
  662.  
  663. INLINE static void
  664. flash(v)
  665.     SCREEN *v;
  666. {
  667.     char *place;
  668.     ITYPE i, j, vplanes;
  669.  
  670.     vplanes = v->planes + v->planes;
  671.     place = v->cursaddr;
  672.  
  673.     for (j = v->cheight; j > 0; --j) {
  674.         for (i = 0; i < vplanes; i+=2)
  675.             place[i] = ~place[i];
  676.  
  677.         place += v->planesiz;
  678.     }
  679.     v->curstimer = v->period;
  680. }
  681.  
  682. /* actually flash cursor (called from vcon.c) */
  683.  
  684. void xflash()
  685. {
  686.     SCREEN *v = v0x+vcurrent-1;
  687.  
  688.     /* vt00's cursor is handled by TOS... */
  689.     if (!vcurrent || v->hidecnt)
  690.         return;
  691.     if ((CURS_FLASH|CURS_ON) == (v->flags & (CURS_FLASH|CURS_ON))) {
  692.         flash(v);
  693.         v->flags ^= CURS_FSTATE;
  694.     }
  695. }
  696.  
  697. /* make sure the cursor is off */
  698.  
  699. INLINE
  700. static void
  701. curs_off(v)
  702.     SCREEN *v;
  703. {
  704.     if (v->flags & CURS_ON) {
  705.         if (v->flags & CURS_FSTATE) {
  706.             flash(v);
  707.             v->flags &= ~CURS_FSTATE;
  708.         }
  709.     }
  710. }
  711.  
  712. /* OK, show the cursor again (if appropriate) */
  713.  
  714. INLINE static void
  715. curs_on(v)
  716.     SCREEN *v;
  717. {
  718.     if (v->hidecnt) return;
  719.  
  720.     if (v->flags & CURS_ON) {
  721. #if 0
  722.     /* if the cursor is flashing, we cheat a little and leave it off
  723.      * to be turned on again (if necessary) by the VBL routine
  724.      */
  725.         if (v->flags & CURS_FLASH) {
  726.             v->curstimer = 2;
  727.             return;
  728.         }
  729. #endif
  730.         if (!(v->flags & CURS_FSTATE)) {
  731.             /* if you can't see the cursor there's no
  732.                reason to flash it */
  733.             if ((v->flags & CURS_FLASH) &&
  734.                 v != v00 && (!vcurrent || !v->v.t.on))
  735.                 return;
  736.             v->flags |= CURS_FSTATE;
  737.             flash(v);
  738.         }
  739.     }
  740. }
  741.  
  742. #ifdef __GNUC__
  743. #define lineA0()                \
  744. ({    register char *retvalue __asm__("d0");    \
  745.     __asm__ volatile("            \
  746.     .word    0xa000 "            \
  747.     : "=r"(retvalue)            \
  748.     :                    \
  749.     : "d0", "d1", "d2", "a0", "a1", "a2"    \
  750.     );                    \
  751.     retvalue;                \
  752. })
  753. #endif
  754.  
  755. /* init vt0[1-9] SCREEN struct */
  756.  
  757. void
  758. init_screen(v, vbase, rowlist, on)
  759.     SCREEN *v;
  760.     char *vbase, *rowlist;
  761.     short on;
  762. {
  763.     static char initv00[sizeof (SCREEN) - offsetof (SCREEN, cheight)];
  764.  
  765.     if (on)
  766.         memmove (initv00, (char *)&v00->cheight, sizeof (initv00));
  767.     bzero ((char *)v, offsetof (SCREEN, cheight));
  768.     memmove ((char *)&v->cheight, initv00, sizeof (initv00));
  769.  
  770.     v->v.t.vbase = vbase;
  771.     v->v.t.rowlist = rowlist;
  772.     v->v.t.on = on;
  773.     v->v.t.state = normal_putch;
  774.     v->cursaddr = vbase;
  775.     v->cx = 0; v->cy = 0;
  776.     v->flags = CURS_ON|CURS_FLASH|FWRAP;
  777.     setbgcol(v, v->bgcol);
  778.     setfgcol(v, v->fgcol);
  779.     clear(v);
  780. }
  781.  
  782. void
  783. init()
  784. {
  785.     SCREEN *v;
  786.     int i, j;
  787.     char *data, *foo;
  788.     static char chardata[256*16];
  789.     register int linelen;
  790.  
  791.     foo = lineA0();
  792.     v = v00 = (SCREEN *)(foo - 346);
  793.     
  794.     /* Ehem... The screen might be bigger than 32767 bytes.
  795.        Let's do some casting... 
  796.        Erling
  797.     */
  798.     linelen = v->linelen;
  799.     scrnsize = (v->maxy+1)*(long)linelen;
  800.     rowoff = (char *)kmalloc((long)((v->maxy+1) * sizeof(long) * (N_VT-1)));
  801.     if (rowoff == 0) {
  802.         FATAL("Insufficient memory for screen offset table!");
  803.     } else {
  804.         long off, *lptr = (long *)rowoff;
  805.         SCREEN *vp = v0x+1;
  806.  
  807.         for (i=0, off=0; i<=v->maxy; i++) {
  808.             *lptr++ = off;
  809.             off += linelen;
  810.         }
  811.         for (i=0; i<N_VT-1; i++) {
  812.             (vp++)->v.t.rowlist = (char *)lptr;
  813.             lptr += v->maxy+1;
  814.         }
  815.     }
  816.     if (hardscroll == -1) {
  817.     /* request for auto-setting */
  818.         hardscroll = v->maxy+1;
  819.     }
  820.     if (!hardbase) {
  821.         hardbase = (char *)(((long)kcore(SCNSIZE(v)+256L)+255L)
  822.                        & 0xffffff00L);
  823.         if (hardbase == 0)
  824.             FATAL("Insufficient memory for second screen buffer!");
  825.         init_screen(v0x, hardbase, rowoff, V_FREE);
  826.     }
  827.     hardline = 0;
  828.     if (v->cheight == 8 && v->planes == 2) {
  829.         foo = &chardata[0];
  830.         vpaint = paint8c;
  831.         for (i = 0; i < 256; i++) {
  832.             chartab[i] = foo;
  833.             data = v->fontdata + i;
  834.             for (j = 0; j < 8; j++) {
  835.                 *foo++ = *data;
  836.                 data += v->form_width;
  837.             }
  838.         }
  839.     } else if ((v->cheight == 16 || v->cheight == 8) && v->planes == 1) {
  840.         foo = &chardata[0];
  841.         vpaint = paint816m;
  842.         for (i = 0; i < 256; i++) {
  843.             chartab[i] = foo;
  844.             data = v->fontdata + i;
  845.             for (j = 0; j < v->cheight; j++) {
  846.                 *foo++ = *data;
  847.                 data += v->form_width;
  848.             }
  849.         }
  850.     }
  851.     else
  852.         vpaint = paint;
  853.  
  854.     if (v->hidecnt == 0) {
  855.     /*
  856.      * make sure the cursor is set up correctly and turned on
  857.      */
  858.         (void)Cursconf(0,0);    /* turn cursor off */
  859.  
  860.         v->flags &= ~CURS_FSTATE;
  861.  
  862.     /* now turn the cursor on the way we like it */
  863.         v->curstimer = v->period;
  864.         v->hidecnt = 0;
  865.         v->flags |= CURS_ON;
  866.         curs_on(v);
  867.     } else {
  868.         (void)Cursconf(0,0);
  869.         v->flags &= ~CURS_ON;
  870.         v->hidecnt = 1;
  871.     }
  872.  
  873.     /* setup bgmask and fgmask */
  874.     setbgcol(v, v->bgcol);
  875.     setfgcol(v, v->fgcol);
  876.     *V_STATE(v) = normal_putch;
  877. }
  878.  
  879. /* deinit, must be called after last close */
  880.  
  881. void
  882. deinit()
  883. {
  884.     kfree (rowoff);
  885. }
  886.  
  887. /* exchange memory, assumes pointers word-aligned and bytes
  888.    multiple of sizeof long...  (faster implementations welcome :-)
  889. */
  890.  
  891. INLINE
  892. void
  893. exchangeb(x1, x2, bytes)
  894.     void *x1, *x2;
  895.     long bytes;
  896. {
  897.     long *p, *q, t;
  898.  
  899.     for (p = x1, q = x2; bytes > 0; bytes -= sizeof (long)) {
  900.         t = *p;
  901.         *p++ = *q;
  902.         *q++ = t;
  903.     }
  904. }
  905.  
  906. /*
  907.  * PLACE(v, x, y): the address corresponding to the upper left hand corner of
  908.  * the character at position (x,y) on screen v
  909.  */
  910. INLINE static
  911. char *PLACE(v, x, y)
  912.     SCREEN *v;
  913.     int x, y;
  914. {
  915.     char *place;
  916.     int i, j;
  917.  
  918.     if (V_LINEAR_P(v)) {
  919.         place = V_BASE(v) + x;
  920.         if (y == v->maxy)
  921.             place += scrnsize - v->linelen;
  922.         else if (y) {
  923.             y+=y;    /* Make Y into index for longword array. */
  924.             y+=y;    /* Two word-size adds are faster than a 2-bit shift. */
  925.             place += *(long *)(rowoff + y);
  926.         }
  927.     } else {
  928.         y+=y;    /* Make Y into index for longword array. */
  929.         y+=y;    /* Two word-size adds are faster than a 2-bit shift. */
  930.         place = V_LINE(v, y) + x;
  931.     }
  932.     if ((j = v->planes-1)) {
  933.         i = (x & 0xfffe);
  934.         do place += i;
  935.         while (--j);
  936.     }
  937.     return place;
  938. }
  939.  
  940. int
  941. setcurrent(vt)
  942.     int vt;
  943. {
  944.     static int v0xcurrent = 1;
  945.     SCREEN *v = VT_SCREEN(vt);
  946.  
  947.     /* are we changing to a `stored' screen? */
  948.     if (vt && vt != v0xcurrent) {
  949.         SCREEN *oldv = VT_SCREEN(v0xcurrent);
  950.         char *foo, *vline = oldv->v.t.vbase;
  951.         int i;
  952.  
  953.         if (!v->v.t.vbase)
  954.             /* sorry terminal closed, has no screen memory */
  955.             return 1;
  956.  
  957.         /* exchange screen contents... */
  958.         for (i=0; i<=v->maxy*sizeof (long); i+=sizeof (long)) {
  959.             exchangeb (vline, V_LINE(v, i), v->linelen);
  960.             vline += v->linelen;
  961.         }
  962.         /* and pointers... */
  963.         foo = oldv->v.t.vbase;
  964.         oldv->v.t.vbase = v->v.t.vbase;
  965.         v->v.t.vbase = foo;
  966.         foo = oldv->v.t.rowlist;
  967.         oldv->v.t.rowlist = v->v.t.rowlist;
  968.         v->v.t.rowlist = foo;
  969.  
  970.         /* free screen memory if told so */
  971.         if (oldv->v.t.on == V_FREE) {
  972.             oldv->v.t.on = 0;
  973.             kfree (oldv->v.t.vbase);
  974.             oldv->v.t.vbase = 0;
  975.         } else {
  976.             oldv->v.t.on = 0;
  977.             oldv->cursaddr = PLACE(oldv, oldv->cx, oldv->cy);
  978.         }
  979.         v->v.t.on = V_USED;
  980.         v->cursaddr = PLACE(v, v->cx, v->cy);
  981.         v0xcurrent = vt;
  982.     }
  983.     vcurrent = vt;
  984.     if (vt && (v->flags & CURS_FLASH))
  985.         curs_on(v);
  986.     Setscreen(-1l, V_BASE(v), -1);
  987.     return 0;
  988. }
  989.  
  990. /*
  991.  * paint(v, c, place): put character 'c' at position 'place' on screen
  992.  * v. It is assumed that x, y are proper coordinates!
  993.  * Specialized versions (paint8c and paint816m) of this routine follow;
  994.  * they assume 8 line high characters, medium res. and 8 or 16 line/mono,
  995.  * respectively.
  996.  */
  997.  
  998. static void
  999. paint(v, c, place)
  1000.     SCREEN *v;
  1001.     int c;
  1002.     char *place;
  1003. {
  1004.     char *data, d, doinverse;
  1005.     ITYPE j, planecount;
  1006.     int vplanes;
  1007.     long vform_width, vplanesiz;
  1008.     int *fgmaskv = V_FGMASK(v), *bgmaskv = V_BGMASK(v);
  1009.  
  1010.     vplanes = v->planes;
  1011.  
  1012.     data = v->fontdata + c;
  1013.     doinverse = (v->flags & FINVERSE) ? 0xff : 0;
  1014.     vform_width = v->form_width;
  1015.     vplanesiz = v->planesiz;
  1016.  
  1017.     for (j = v->cheight-1; j > 0; --j) {
  1018.         d = *data ^ doinverse;
  1019.         for (planecount = 0; planecount < vplanes; planecount++)
  1020.           place[planecount << 1]
  1021.             = ((d & (char) fgmaskv[planecount])
  1022.                | (~d & (char) bgmaskv[planecount]));
  1023.         place += vplanesiz;
  1024.         data += vform_width;
  1025.     }
  1026.     d = ((v->flags & FUNDERLINE) ? -1 : *data) ^ doinverse;
  1027.     for (planecount = 0; planecount < vplanes; planecount++)
  1028.       place[planecount << 1]
  1029.         = ((d & (char) fgmaskv[planecount])
  1030.            | (~d & (char) bgmaskv[planecount]));
  1031. }
  1032.  
  1033. static void
  1034. paint8c(v, c, place)
  1035.     SCREEN *v;
  1036.     int c;
  1037.     char *place;
  1038. {
  1039.     char *data;
  1040.     char d, doinverse, dounderline;
  1041.     char bg0, bg1, fg0, fg1;
  1042.     long vplanesiz;
  1043.     int *m;
  1044.  
  1045.     data = chartab[c];
  1046.  
  1047.     doinverse = (v->flags & FINVERSE) ? 0xff : 0;
  1048.     dounderline = (v->flags & FUNDERLINE) ? 0xff : 0;
  1049.     vplanesiz = v->planesiz;
  1050.     m = V_BGMASK(v);
  1051.     bg0 = *m++;
  1052.     bg1 = *m++;
  1053.     m = V_FGMASK(v);
  1054.     fg0 = *m++;
  1055.     fg1 = *m++;
  1056.  
  1057.     if (!doinverse && !bg0 && !bg1 && fg0 && fg1) {
  1058.         /* line 1 */
  1059.         d = *data++;
  1060.         *place = d;
  1061.         place[2] = d;
  1062.         place += vplanesiz;
  1063.  
  1064.         /* line 2 */
  1065.         d = *data++;
  1066.         *place = d;
  1067.         place[2] = d;
  1068.         place += vplanesiz;
  1069.  
  1070.         /* line 3 */
  1071.         d = *data++;
  1072.         *place = d;
  1073.         place[2] = d;
  1074.         place += vplanesiz;
  1075.  
  1076.         /* line 4 */
  1077.         d = *data++;
  1078.         *place = d;
  1079.         place[2] = d;
  1080.         place += vplanesiz;
  1081.  
  1082.         /* line 5 */
  1083.         d = *data++;
  1084.         *place = d;
  1085.         place[2] = d;
  1086.         place += vplanesiz;
  1087.  
  1088.         /* line 6 */
  1089.         d = *data++;
  1090.         *place = d;
  1091.         place[2] = d;
  1092.         place += vplanesiz;
  1093.  
  1094.         /* line 7 */
  1095.         d = *data++;
  1096.         *place = d;
  1097.         place[2] = d;
  1098.         place += vplanesiz;
  1099.  
  1100.         /* line 8 */
  1101.         d = *data | dounderline;
  1102.         *place = d;
  1103.         place[2] = d;
  1104.     } else {
  1105.         /* line 1 */
  1106.         d = *data++ ^ doinverse;
  1107.         *place = ((d & fg0) | (~d & bg0));
  1108.         place[2] = ((d & fg1) | (~d & bg1));
  1109.         place += vplanesiz;
  1110.  
  1111.         /* line 2 */
  1112.         d = *data++ ^ doinverse;
  1113.         *place = ((d & fg0) | (~d & bg0));
  1114.         place[2] = ((d & fg1) | (~d & bg1));
  1115.         place += vplanesiz;
  1116.  
  1117.         /* line 3 */
  1118.         d = *data++ ^ doinverse;
  1119.         *place = ((d & fg0) | (~d & bg0));
  1120.         place[2] = ((d & fg1) | (~d & bg1));
  1121.         place += vplanesiz;
  1122.  
  1123.         /* line 4 */
  1124.         d = *data++ ^ doinverse;
  1125.         *place = ((d & fg0) | (~d & bg0));
  1126.         place[2] = ((d & fg1) | (~d & bg1));
  1127.         place += vplanesiz;
  1128.  
  1129.         /* line 5 */
  1130.         d = *data++ ^ doinverse;
  1131.         *place = ((d & fg0) | (~d & bg0));
  1132.         place[2] = ((d & fg1) | (~d & bg1));
  1133.         place += vplanesiz;
  1134.  
  1135.         /* line 6 */
  1136.         d = *data++ ^ doinverse;
  1137.         *place = ((d & fg0) | (~d & bg0));
  1138.         place[2] = ((d & fg1) | (~d & bg1));
  1139.         place += vplanesiz;
  1140.  
  1141.         /* line 7 */
  1142.         d = *data++ ^ doinverse;
  1143.         *place = ((d & fg0) | (~d & bg0));
  1144.         place[2] = ((d & fg1) | (~d & bg1));
  1145.         place += vplanesiz;
  1146.  
  1147.         /* line 8 */
  1148.         d = (*data | dounderline) ^ doinverse;
  1149.         *place = ((d & fg0) | (~d & bg0));
  1150.         place[2] = ((d & fg1) | (~d & bg1));
  1151.     }
  1152. }
  1153.  
  1154. static void
  1155. paint816m(v, c, place)
  1156.     SCREEN *v;
  1157.     int c;
  1158.     char *place;
  1159. {
  1160.     char *data;
  1161.     char d, doinverse, dounderline;
  1162.     long vplanesiz;
  1163.  
  1164.     data = chartab[c];
  1165.     doinverse = (v->flags & FINVERSE) ? 0xff : 0;
  1166.     doinverse ^= (d = V_BGMASK(v)[0]);
  1167.     dounderline = (v->flags & FUNDERLINE) ? 0xff : 0;
  1168.     vplanesiz = v->planesiz;
  1169.  
  1170.     if (d == V_FGMASK(v)[0])
  1171.       {
  1172.         /* fgcol and bgcol are the same -- easy */
  1173.         *place = d;
  1174.         place += vplanesiz;
  1175.         *place = d;
  1176.         place += vplanesiz;
  1177.         *place = d;
  1178.         place += vplanesiz;
  1179.         *place = d;
  1180.         place += vplanesiz;
  1181.         *place = d;
  1182.         place += vplanesiz;
  1183.         *place = d;
  1184.         place += vplanesiz;
  1185.         *place = d;
  1186.         place += vplanesiz;
  1187.         *place = d;
  1188.         if (v->cheight == 8)
  1189.         return;
  1190.         place += vplanesiz;
  1191.         *place = d;
  1192.         place += vplanesiz;
  1193.         *place = d;
  1194.         place += vplanesiz;
  1195.         *place = d;
  1196.         place += vplanesiz;
  1197.         *place = d;
  1198.         place += vplanesiz;
  1199.         *place = d;
  1200.         place += vplanesiz;
  1201.         *place = d;
  1202.         place += vplanesiz;
  1203.         *place = d;
  1204.         place += vplanesiz;
  1205.         *place = d;
  1206.       }
  1207.     else if (!doinverse) {
  1208.         /* line 1 */
  1209.         d = *data++;
  1210.         *place = d;
  1211.         place += vplanesiz;
  1212.  
  1213.         /* line 2 */
  1214.         d = *data++;
  1215.         *place = d;
  1216.         place += vplanesiz;
  1217.  
  1218.         /* line 3 */
  1219.         d = *data++;
  1220.         *place = d;
  1221.         place += vplanesiz;
  1222.  
  1223.         /* line 4 */
  1224.         d = *data++;
  1225.         *place = d;
  1226.         place += vplanesiz;
  1227.  
  1228.         /* line 5 */
  1229.         d = *data++;
  1230.         *place = d;
  1231.         place += vplanesiz;
  1232.  
  1233.         /* line 6 */
  1234.         d = *data++;
  1235.         *place = d;
  1236.         place += vplanesiz;
  1237.  
  1238.         /* line 7 */
  1239.         d = *data++;
  1240.         *place = d;
  1241.         place += vplanesiz;
  1242.  
  1243.         /* line 8 */
  1244.         d = *data++;
  1245.         if (v->cheight == 8) {
  1246.             *place = d | dounderline;
  1247.             return;
  1248.         }
  1249.         *place = d;
  1250.  
  1251.         place += vplanesiz;
  1252.  
  1253.         /* line 9 */
  1254.         d = *data++;
  1255.         *place = d;
  1256.         place += vplanesiz;
  1257.  
  1258.         /* line 10 */
  1259.         d = *data++;
  1260.         *place = d;
  1261.         place += vplanesiz;
  1262.  
  1263.         /* line 11 */
  1264.         d = *data++;
  1265.         *place = d;
  1266.         place += vplanesiz;
  1267.  
  1268.         /* line 12 */
  1269.         d = *data++;
  1270.         *place = d;
  1271.         place += vplanesiz;
  1272.  
  1273.         /* line 13 */
  1274.         d = *data++;
  1275.         *place = d;
  1276.         place += vplanesiz;
  1277.  
  1278.         /* line 14 */
  1279.         d = *data++;
  1280.         *place = d;
  1281.         place += vplanesiz;
  1282.  
  1283.         /* line 15 */
  1284.         d = *data++;
  1285.         *place = d;
  1286.         place += vplanesiz;
  1287.  
  1288.         /* line 16 */
  1289.         d = *data;
  1290.         *place = d | dounderline;
  1291.     } else {
  1292.         /* line 1 */
  1293.         d = ~*data++;
  1294.         *place = d;
  1295.         place += vplanesiz;
  1296.  
  1297.         /* line 2 */
  1298.         d = ~*data++;
  1299.         *place = d;
  1300.         place += vplanesiz;
  1301.  
  1302.         /* line 3 */
  1303.         d = ~*data++;
  1304.         *place = d;
  1305.         place += vplanesiz;
  1306.  
  1307.         /* line 4 */
  1308.         d = ~*data++;
  1309.         *place = d;
  1310.         place += vplanesiz;
  1311.  
  1312.         /* line 5 */
  1313.         d = ~*data++;
  1314.         *place = d;
  1315.         place += vplanesiz;
  1316.  
  1317.         /* line 6 */
  1318.         d = ~*data++;
  1319.         *place = d;
  1320.         place += vplanesiz;
  1321.  
  1322.         /* line 7 */
  1323.         d = ~*data++;
  1324.         *place = d;
  1325.         place += vplanesiz;
  1326.  
  1327.         /* line 8 */
  1328.         d = ~*data++;
  1329.         if (v->cheight == 8) {
  1330.             *place = d | dounderline;
  1331.             return;
  1332.         }
  1333.         *place = d;
  1334.  
  1335.         place += vplanesiz;
  1336.  
  1337.         /* line 9 */
  1338.         d = ~*data++;
  1339.         *place = d;
  1340.         place += vplanesiz;
  1341.  
  1342.         /* line 10 */
  1343.         d = ~*data++;
  1344.         *place = d;
  1345.         place += vplanesiz;
  1346.  
  1347.         /* line 11 */
  1348.         d = ~*data++;
  1349.         *place = d;
  1350.         place += vplanesiz;
  1351.  
  1352.         /* line 12 */
  1353.         d = ~*data++;
  1354.         *place = d;
  1355.         place += vplanesiz;
  1356.  
  1357.         /* line 13 */
  1358.         d = ~*data++;
  1359.         *place = d;
  1360.         place += vplanesiz;
  1361.  
  1362.         /* line 14 */
  1363.         d = ~*data++;
  1364.         *place = d;
  1365.         place += vplanesiz;
  1366.  
  1367.         /* line 15 */
  1368.         d = ~*data++;
  1369.         *place = d;
  1370.         place += vplanesiz;
  1371.  
  1372.         /* line 16 */
  1373.         d = ~*data;
  1374.         *place = d | dounderline;
  1375.     }
  1376. }
  1377.  
  1378. /*
  1379.  * gotoxy (v, x, y): move current cursor address of screen v to (x, y)
  1380.  * makes sure that (x, y) will be legal
  1381.  */
  1382.  
  1383. INLINE static void
  1384. gotoxy(v, x, y)
  1385.     SCREEN *v;
  1386.     int x, y;
  1387. {
  1388.     if (x > v->maxx) x = v->maxx;
  1389.     else if (x < 0) x = 0;
  1390.     if (y > v->maxy) y = v->maxy;
  1391.     else if (y < 0) y = 0;
  1392.  
  1393.     v->cx = x;
  1394.     v->cy = y;
  1395.     v->cursaddr = PLACE(v, x, y);
  1396. }
  1397.  
  1398. /*
  1399.  * clrline(v, r): clear line r of screen v
  1400.  */
  1401.  
  1402. INLINE static void
  1403. clrline(v, r)
  1404.     SCREEN *v;
  1405.     int r;
  1406. {
  1407.     int *dst, *m;
  1408.     long nwords;
  1409.     int i, vplanes = v->planes;
  1410.  
  1411.     /* Hey, again the screen might be bigger than 32767 bytes.
  1412.        Do another cast... */
  1413.     r += r;
  1414.     r += r;
  1415.     dst = (int *)(V_LINE(v, r));
  1416.     if (v->bgcol == 0)
  1417.       zero((char *)dst, v->linelen);
  1418.     else if (vplanes == 1)
  1419.       memset ((char *)dst, *V_BGMASK(v), v->linelen);
  1420.     else
  1421.       {
  1422.         /* do it the hard way */
  1423.         for (nwords = v->linelen >> 1; nwords > 0; nwords -= vplanes)
  1424.           {
  1425.         m = V_BGMASK(v);
  1426.         for (i = 0; i < vplanes; i++)
  1427.           *dst++ = *m++;
  1428.           }
  1429.       }
  1430. }
  1431.     
  1432. /*
  1433.  * clear(v): clear the whole screen v
  1434.  */
  1435.  
  1436. INLINE static void
  1437. clear(v)
  1438.     SCREEN *v;
  1439. {
  1440.     int i, vplanes = v->planes;
  1441.     int *dst = (int *) V_BASE(v), *m;
  1442.     long nwords;
  1443.  
  1444.     if (!V_LINEAR_P(v))
  1445.       memmove (v->v.t.rowlist, rowoff, ((v->maxy+1) * sizeof(long)));
  1446.     if (v->bgcol == 0)
  1447.       zero((char *)dst, scrnsize);
  1448.     else if (vplanes == 1)
  1449.       memset ((char *)dst, *V_BGMASK(v), scrnsize);
  1450.     else
  1451.       {
  1452.         /* do it the hard way */
  1453.         for (nwords = scrnsize >> 1; nwords > 0; nwords -= vplanes)
  1454.           {
  1455.         m = V_BGMASK(v);
  1456.         for (i = 0; i < vplanes; i++)
  1457.           *dst++ = *m++;
  1458.           }
  1459.       }
  1460. }
  1461.  
  1462. /*
  1463.  * clrchars(v, x, y, n): clear n chars starting at position (x,y) on screen v
  1464.  */
  1465.  
  1466. /*INLINE*/ static void
  1467. clrchars(v, x, y, n)
  1468.     SCREEN *v;
  1469.     int x, y, n;
  1470. {
  1471.     int i, j, vplanes;
  1472.     char *place;
  1473.     int *m, *l;
  1474.  
  1475.     if (!x && n == v->maxx+1) {
  1476.         clrline(v, y);
  1477.         return;
  1478.     }
  1479.     vplanes = v->planes + v->planes;
  1480.  
  1481.     if (y == v->cy && x == v->cx)
  1482.         place = v->cursaddr;
  1483.     else
  1484.         place = PLACE(v, x, y);
  1485.  
  1486.     l = V_BGMASK(v);
  1487.     if (vplanes > 2) {
  1488.         if (x & 1) {
  1489.             char *p = place;
  1490.             for (j = v->cheight; j > 0; --j) {
  1491.                 char *q = p;
  1492.                 m = l;
  1493.                 for (i = 0; i < vplanes; i += 2) {
  1494.                     *q++ = (char) *m++;
  1495.                     ++q;
  1496.                 }
  1497.                 p += v->planesiz;
  1498.             }
  1499.             place += vplanes-1;
  1500.             --n;
  1501.         }
  1502.         if (n > 1) {
  1503.             int nbytes = n*(vplanes>>1);
  1504.             char *p = place;
  1505.             place += nbytes;
  1506.  
  1507.             if (v->bgcol == 0) {
  1508.                 for (j = v->cheight; j > 0; --j) {
  1509.                     bzero(p, nbytes);
  1510.                     p += v->planesiz;
  1511.                 }
  1512.             } else {
  1513.                 for (j = v->cheight; j > 0; --j) {
  1514.                     short *q = (short *)p;
  1515.                     int k;
  1516.  
  1517.                     for (k = n; k > 1; k -= 2) {
  1518.                         m = l;
  1519.                         for (i = 0; i < vplanes; i += 2)
  1520.                             *q++ = *m++;
  1521.                     }
  1522.                     p += v->planesiz;
  1523.                 }
  1524.             }
  1525.         }
  1526.         if (n & 1) {
  1527.             for (j = v->cheight; j > 0; --j) {
  1528.                 char *p = place;
  1529.                 m = l;
  1530.                 for (i = 0; i < vplanes; i += 2) {
  1531.                     *p++ = (char) *m++;
  1532.                     ++p;
  1533.                 }
  1534.             }
  1535.             place += v->planesiz;
  1536.         }
  1537.     } else {
  1538.         for (j = v->cheight; j > 0; --j) {
  1539.             memset (place, *l, n);
  1540.             place += v->planesiz;
  1541.         }
  1542.     }
  1543. }
  1544.  
  1545. /*
  1546.  * clrfrom(v, x1, y1, x2, y2): clear screen v from position (x1,y1) to
  1547.  * position (x2, y2) inclusive. It is assumed that y2 >= y1.
  1548.  */
  1549.  
  1550. INLINE static void
  1551. clrfrom(v, x1, y1, x2, y2)
  1552.     SCREEN *v;
  1553.     int x1,y1,x2,y2;
  1554. {
  1555.     int i;
  1556.  
  1557.     clrchars(v, x1, y1, (y2 == y1 ? x2 : v->maxx)-x1+1);
  1558.     if (y2 > y1) {
  1559.         for (i = y1+1; i < y2; i++)
  1560.             clrline(v, i);
  1561.         clrchars(v, 0, y2, x2);
  1562.     }
  1563. }
  1564.  
  1565. /*
  1566.  * scroll a screen in hardware; if we still have hardware scrolling lines left,
  1567.  * just move the physical screen base, otherwise copy the screen back to the
  1568.  * hardware base and start over
  1569.  */
  1570. void
  1571. hardware_scroll(v)
  1572.     SCREEN *v;
  1573. {
  1574.  
  1575.     ++hardline;
  1576.     if (hardline < hardscroll) { /* just move the screen */
  1577.         v->v.t.vbase += v->linelen;
  1578.     } else {
  1579.         hardline = 0;
  1580.         quickmove(hardbase, v->v.t.vbase + v->linelen, scrnsize - v->linelen);
  1581.         v->v.t.vbase = hardbase;
  1582.     }
  1583.     v->cursaddr = PLACE(v, v->cx, v->cy);
  1584.     if (vcurrent)
  1585.         Setscreen(-1l, v->v.t.vbase, -1);
  1586. }
  1587.  
  1588. /*
  1589.  * delete_line(v, r): delete line r of screen v. The screen below this
  1590.  * line is scrolled up, and the bottom line is cleared.
  1591.  */
  1592.  
  1593. #define scroll(v) delete_line(v, 0)
  1594.  
  1595. INLINE static void
  1596. delete_line(v, r)
  1597.     SCREEN *v;
  1598.     int r;
  1599. {
  1600.     long *src, *dst, nbytes;
  1601.  
  1602.     /* if this screen needs not be linear (i.e. its `stored' not shown)
  1603.        then just adjust the line offset table...
  1604.     */
  1605.     if (!V_LINEAR_P(v)) {
  1606.         register int i = r + r;
  1607.         long t;
  1608.         i += i;
  1609.         src = (long *)(v->v.t.rowlist+i);
  1610.         i = v->maxy - r;
  1611.         i += i;
  1612.         i += i;
  1613.         t = *src;
  1614.         memmove (src, src+1, i);
  1615.         i = v->maxy + v->maxy;
  1616.         i += i;
  1617.         *(long *)(v->v.t.rowlist+i) = t;
  1618.         clrline(v, v->maxy);
  1619.         return;
  1620.     }
  1621.     if (r == 0) {
  1622.         if (v != v00 & hardscroll > 0) {
  1623.             hardware_scroll(v);
  1624.             clrline(v, v->maxy);
  1625.             return;
  1626.         }
  1627.         nbytes = scrnsize - v->linelen;
  1628.     } else {
  1629.         register int i = v->maxy - r;
  1630.         i += i;
  1631.         i += i;
  1632.         nbytes = *(long *)(rowoff+i);
  1633.     }
  1634.  
  1635.     /* Sheeze, how many times do we really have to cast... 
  1636.        Erling.    
  1637.     */
  1638.  
  1639.     r += r;
  1640.     r += r;
  1641.     dst = (long *)(V_BASE(v) + *(long *)(rowoff + r));
  1642.     src = (long *)( ((long)dst) + v->linelen);
  1643.  
  1644.     quickmove(dst, src, nbytes);
  1645.  
  1646. /* clear the last line */
  1647.     clrline(v, v->maxy);
  1648. }
  1649.  
  1650. void
  1651. hardware_scroll_down(v)
  1652.     SCREEN *v;
  1653. {
  1654.  
  1655.     --hardline;
  1656.     if (hardline >= 0) { /* just move the screen */
  1657.         v->v.t.vbase -= v->linelen;
  1658.     } else {
  1659.         hardline = hardscroll - 1;
  1660.         v->v.t.vbase = hardbase + (long) hardline*v->linelen;
  1661.         memmove(v->v.t.vbase + v->linelen, hardbase, scrnsize - v->linelen);
  1662.     }
  1663.     v->cursaddr = PLACE(v, v->cx, v->cy);
  1664.     if (vcurrent)
  1665.         Setscreen(-1l, v->v.t.vbase, -1);
  1666. }
  1667.  
  1668. /*
  1669.  * insert_line(v, r): scroll all of the screen starting at line r down,
  1670.  * and then clear line r.
  1671.  */
  1672.  
  1673. INLINE static void
  1674. insert_line(v, r)
  1675.     SCREEN *v;
  1676.     int r;
  1677. {
  1678.     long *src, *dst;
  1679.     int i, j, linelen;
  1680.  
  1681.     if (!V_LINEAR_P(v)) {
  1682.         long t;
  1683.         i = r + r;
  1684.         i += i;
  1685.         src = (long *)(v->v.t.rowlist+i);
  1686.         i = v->maxy + v->maxy;
  1687.         i += i;
  1688.         t = *(long *)(v->v.t.rowlist+i);
  1689.         i = v->maxy - r;
  1690.         i += i;
  1691.         i += i;
  1692.         memmove (src+1, src, i);
  1693.         *src = t;
  1694.         clrline(v, r);
  1695.         return;
  1696.     }
  1697.     if (!r && v != v00 & hardscroll > 0) {
  1698.         hardware_scroll_down(v);
  1699.         clrline(v, 0);
  1700.         return;
  1701.     }
  1702.     i = v->maxy - 1;
  1703.     i += i;
  1704.     i += i;
  1705.     j = r+r;
  1706.     j += j;
  1707.     linelen = v->linelen;
  1708.     src = (long *)(V_BASE(v) + *(long *)(rowoff + i));
  1709.     dst = (long *)((long)src + linelen);
  1710.     for (; i >= j ; i -= 4) {
  1711.     /* move line i to line i+1 */
  1712.         quickmove(dst, src, linelen);
  1713.         dst = src;
  1714.         src = (long *)((long) src - linelen);
  1715.     }
  1716.  
  1717. /* clear line r */
  1718.     clrline(v, r);
  1719. }
  1720.  
  1721. /*
  1722.  * special states for handling ESC b x and ESC c x. Note that for now,
  1723.  * color is ignored.
  1724.  */
  1725.  
  1726. static void
  1727. setbgcol(v, c)
  1728.     SCREEN *v;
  1729.     int c;
  1730. {
  1731.     int i;
  1732.     int *m = V_BGMASK(v);
  1733.  
  1734.     v->bgcol = c & ((1 << v->planes)-1);
  1735.     for (i = 0; i < v->planes; i++)
  1736.         *m++ = (v->bgcol & (1 << i)) ? -1 : 0;
  1737.     *V_STATE(v) = normal_putch;
  1738. }
  1739.  
  1740. static void
  1741. setfgcol(v, c)
  1742.     SCREEN *v;
  1743.     int c;
  1744. {
  1745.     int i;
  1746.     int *m = V_FGMASK(v);
  1747.  
  1748.     v->fgcol = c & ((1 << v->planes)-1);
  1749.     for (i = 0; i < v->planes; i++)
  1750.         *m++ = (v->fgcol & (1 << i)) ? -1 : 0;
  1751.     *V_STATE(v) = normal_putch;
  1752. }
  1753.  
  1754. static void
  1755. setcurs(v, c)
  1756.     SCREEN *v;
  1757.     int c;
  1758. {
  1759.     c -= ' ';
  1760.     if (!c) {
  1761.         v->flags &= ~CURS_FLASH;
  1762.     } else {
  1763.         v->flags |= CURS_FLASH;
  1764.         v->period = (unsigned char) c;
  1765.     }
  1766.     *V_STATE(v) = normal_putch;
  1767. }
  1768.  
  1769. /* set special effects...  FIXME: only inverse and underline do anything */
  1770. static void
  1771. seffect_putch(v, c)
  1772.     SCREEN *v;
  1773.     int c;
  1774. {
  1775.     v->flags |= ((c & 0x10) ? FINVERSE : 0)|((c & 0x8) ? FUNDERLINE : 0);
  1776.     *V_STATE(v) = normal_putch;
  1777. }
  1778.  
  1779. /* clear special effects */
  1780. static void
  1781. ceffect_putch(v, c)
  1782.     SCREEN *v;
  1783.     int c;
  1784. {
  1785.     v->flags &= ~(((c & 0x10) ? FINVERSE : 0)|((c & 0x8) ? FUNDERLINE : 0));
  1786.     *V_STATE(v) = normal_putch;
  1787. }
  1788.  
  1789. static void
  1790. quote_putch(v, c)
  1791.     SCREEN *v;
  1792.     int c;
  1793. {
  1794.     (*vpaint)(v, c, v->cursaddr);
  1795.     *V_STATE(v) = normal_putch;
  1796. }
  1797.  
  1798. /*
  1799.  * putesc(v, c): handle the control sequence ESC c
  1800.  */
  1801.  
  1802. static void
  1803. putesc(v, c)
  1804.     SCREEN *v;
  1805.     int c;
  1806. {
  1807.     int i;
  1808.     int cx, cy;
  1809.  
  1810.     cx = v->cx; cy = v->cy;
  1811.  
  1812.     switch (c) {
  1813.     case 'A':        /* cursor up */
  1814.         if (cy) {
  1815. moveup:            v->cy = --cy;
  1816.             if (V_LINEAR_P(v))
  1817.                 v->cursaddr -= v->linelen;
  1818.             else {
  1819.                 long *r;
  1820.                 i = cy + cy;
  1821.                 i += i;
  1822.                 r = (long *)(v->v.t.rowlist+i);
  1823.                 v->cursaddr -= r[1] - r[0];
  1824.             }
  1825.         }
  1826.         break;
  1827.     case 'B':        /* cursor down */
  1828.         if (cy < v->maxy) {
  1829.             v->cy = ++cy;
  1830.             if (V_LINEAR_P(v))
  1831.                 v->cursaddr += v->linelen;
  1832.             else {
  1833.                 long *r;
  1834.                 i = cy + cy;
  1835.                 i += i;
  1836.                 r = (long *)(v->v.t.rowlist+i);
  1837.                 v->cursaddr += r[0] - r[-1];
  1838.             }
  1839.         }
  1840.         break;
  1841.     case 'C':        /* cursor right */
  1842.         if (cx < v->maxx) {
  1843.             if ((i = v->planes-1) && (cx & 1))
  1844.                 v->cursaddr += i + i;
  1845.             v->cx = ++cx;
  1846.             v->cursaddr++;
  1847.         }
  1848.         break;
  1849.     case 'D':        /* cursor left */
  1850.         if (cx) {
  1851.             v->cx = --cx;
  1852.             v->cursaddr--;
  1853.             if ((i = v->planes-1) && (cx & 1))
  1854.                 v->cursaddr -= i + i;
  1855.         }
  1856.         break;
  1857.     case 'E':        /* clear home */
  1858.         clear(v);
  1859.         /* fall through... */
  1860.     case 'H':        /* cursor home */
  1861.         v->cx = 0; v->cy = 0;
  1862.         v->cursaddr = V_LINE(v, 0);
  1863.         break;
  1864.     case 'I':        /* cursor up, insert line */
  1865.         if (cy == 0) {
  1866.             insert_line(v, 0);
  1867.             if (!V_LINEAR_P(v)) {
  1868.                 long *r;
  1869.                 i = cy + cy;
  1870.                 i += i;
  1871.                 r = (long *)(v->v.t.rowlist+i);
  1872.                 v->cursaddr -= r[1] - r[0];
  1873.             }
  1874.         }
  1875.         else
  1876.             goto moveup;
  1877.         break;
  1878.     case 'J':        /* clear below cursor */
  1879.         clrfrom(v, cx, cy, v->maxx, v->maxy);
  1880.         break;
  1881.     case 'K':        /* clear remainder of line */
  1882.         clrfrom(v, cx, cy, v->maxx, cy);
  1883.         break;
  1884.     case 'L':        /* insert a line */
  1885.         v->cx = 0;
  1886.         i = cy + cy;
  1887.         i += i;
  1888.         insert_line(v, cy);
  1889.         v->cursaddr = V_LINE(v, i);
  1890.         break;
  1891.     case 'M':        /* delete line */
  1892.         v->cx = 0;
  1893.         i = cy + cy;
  1894.         i += i;
  1895.         delete_line(v, cy);
  1896.         v->cursaddr = V_LINE(v, i);
  1897.         break;
  1898.     case 'Q':        /* EXTENSION: quote-next-char */
  1899.         *V_STATE(v) = quote_putch;
  1900.         return;
  1901.     case 'Y':
  1902.         *V_STATE(v) = escy_putch;
  1903.         return;        /* YES, this should be 'return' */
  1904.  
  1905.     case 'b':
  1906.         *V_STATE(v) = setfgcol;
  1907.         return;
  1908.     case 'c':
  1909.         *V_STATE(v) = setbgcol;
  1910.         return;
  1911.     case 'd':        /* clear to cursor position */
  1912.         clrfrom(v, 0, 0, cx, cy);
  1913.         break;
  1914.     case 'e':        /* enable cursor */
  1915.         v->flags |= CURS_ON;
  1916.         v->hidecnt = 1;    /* so --v->hidecnt shows the cursor */
  1917.         break;
  1918.     case 'f':        /* cursor off */
  1919.         v->hidecnt++;
  1920.         v->flags &= ~CURS_ON;
  1921.         break;
  1922.     case 'j':        /* save cursor position */
  1923.         v->savex = v->cx;
  1924.         v->savey = v->cy;
  1925.         break;
  1926.     case 'k':        /* restore saved position */
  1927.         gotoxy(v, v->savex, v->savey);
  1928.         break;
  1929.     case 'l':        /* clear line */
  1930.         v->cx = 0;
  1931.         i = cy + cy;
  1932.         i += i;
  1933.         v->cursaddr = V_LINE(v, i);
  1934.         clrline(v, cy);
  1935.         break;
  1936.     case 'o':        /* clear from start of line to cursor */
  1937.         clrfrom(v, 0, cy, cx, cy);
  1938.         break;
  1939.     case 'p':        /* reverse video on */
  1940.         v->flags |= FINVERSE;
  1941.         break;
  1942.     case 'q':        /* reverse video off */
  1943.         v->flags &= ~FINVERSE;
  1944.         break;
  1945.     case 't':        /* EXTENSION: set cursor flash rate */
  1946.         *V_STATE(v) = setcurs;
  1947.         return;
  1948.     case 'v':        /* wrap on */
  1949.         v->flags |= FWRAP;
  1950.         break;
  1951.     case 'w':
  1952.         v->flags &= ~FWRAP;
  1953.         break;
  1954.     case 'y':        /* EXTENSION: set special effects */
  1955.         *V_STATE(v) = seffect_putch;
  1956.         curs_on(v);
  1957.         return;
  1958.     case 'z':        /* EXTENSION: clear special effects */
  1959.         *V_STATE(v) = ceffect_putch;
  1960.         curs_on(v);
  1961.         return;
  1962.     }
  1963.     *V_STATE(v) = normal_putch;
  1964. }
  1965.  
  1966. /*
  1967.  * escy1_putch(v, c): for when an ESC Y + char has been seen
  1968.  */
  1969. static void
  1970. escy1_putch(v, c)
  1971.     SCREEN *v;
  1972.     int c;
  1973. {
  1974.     /* some (un*x) termcaps seem to always set the hi bit on
  1975.        cm args (cm=\EY%+ %+ :) -> drop that unless the screen
  1976.        is bigger.    -nox
  1977.     */
  1978.     gotoxy(v, (c-' ') & (v->maxx|0x7f), (V_ESCY1(v)-' ') & (v->maxy|0x7f));
  1979.     *V_STATE(v) = normal_putch;
  1980. }
  1981.  
  1982. /*
  1983.  * escy_putch(v, c): for when an ESC Y has been seen
  1984.  */
  1985. static void
  1986. escy_putch(v, c)
  1987.     SCREEN *v;
  1988.     int c;
  1989. {
  1990.     V_ESCY1(v) = c;
  1991.     *V_STATE(v) = escy1_putch;
  1992. }
  1993.  
  1994. /*
  1995.  * normal_putch(v, c): put character 'c' on screen 'v'. This is the default
  1996.  * for when no escape, etc. is active
  1997.  */
  1998.  
  1999. static void
  2000. normal_putch(v, c)
  2001.     SCREEN *v;
  2002.     int c;
  2003. {
  2004.     register int i;
  2005.  
  2006. /* control characters */
  2007.     if (c < ' ') {
  2008.         switch (c) {
  2009.         case '\r':
  2010. col0:            v->cx = 0;
  2011.             i = v->cy + v->cy;
  2012.             i += i;
  2013.             v->cursaddr = V_LINE(v, i);
  2014.             return;
  2015.         case '\n':
  2016.             if (v->cy == v->maxy) {
  2017.                 scroll(v);
  2018.                 if (!V_LINEAR_P(v)) {
  2019.                     long *r;
  2020.                     i = v->cy + v->cy;
  2021.                     i += i;
  2022.                     r = (long *)(v->v.t.rowlist+i);
  2023.                     v->cursaddr += r[0] - r[-1];
  2024.                 }
  2025.             } else {
  2026.                 v->cy++;
  2027.                 if (V_LINEAR_P(v))
  2028.                     v->cursaddr += v->linelen;
  2029.                 else {
  2030.                     long *r;
  2031.                     i = v->cy + v->cy;
  2032.                     i += i;
  2033.                     r = (long *)(v->v.t.rowlist+i);
  2034.                     v->cursaddr += r[0] - r[-1];
  2035.                 }
  2036.             }
  2037.             return;
  2038.         case '\b':
  2039.             if (v->cx) {
  2040.                 v->cx--;
  2041.                 v->cursaddr--;
  2042.                 if ((i = v->planes-1) && (v->cx & 1))
  2043.                     v->cursaddr -= i+i;
  2044.             }
  2045.             return;
  2046.         case '\007':        /* BELL */
  2047.             (void)bconout(CONDEV, 7);
  2048.             return;
  2049.         case '\033':        /* ESC */
  2050.             *V_STATE(v) = putesc;
  2051.             return;
  2052.         case '\t':
  2053.             if (v->cx < v->maxx) {
  2054.             /* this can't be register for an ANSI compiler */
  2055.                 union {
  2056.                     long l;
  2057.                     short i[2];
  2058.                 } j;
  2059.                 j.l = 0;
  2060.                 j.i[1] = 8 - (v->cx & 7);
  2061.                 v->cx += j.i[1];
  2062.                 if (v->cx - v->maxx > 0) {
  2063.                     j.i[1] = v->cx - v->maxx;
  2064.                     v->cx = v->maxx;
  2065.                 }
  2066.                 v->cursaddr += j.l;
  2067.                 if ((i = v->planes-1)) {
  2068.                     if (j.l & 1)
  2069.                         j.i[1]++;
  2070.                     do v->cursaddr += j.l;
  2071.                     while (--i);
  2072.                 }
  2073.             }
  2074.             return;
  2075.         default:
  2076.             return;
  2077.         }
  2078.     }
  2079.  
  2080.     (*vpaint)(v, c, v->cursaddr);
  2081.     v->cx++;
  2082.     if (v->cx > v->maxx) {
  2083.         if (v->flags & FWRAP) {
  2084.             normal_putch(v, '\n');
  2085.             goto col0;
  2086.         } else {
  2087.             v->cx = v->maxx;
  2088.         }
  2089.     } else {
  2090.         v->cursaddr++;
  2091.         if ((i = v->planes-1) && !(v->cx & 1))    /* new word */
  2092.             v->cursaddr += i + i;
  2093.     }
  2094. }
  2095.  
  2096. INLINE static void
  2097. put_ch00(v, c)
  2098.     SCREEN *v;
  2099.     int c;
  2100. {
  2101.     (*v00state)(v, c & 0x00ff);
  2102. }
  2103.  
  2104. INLINE static void
  2105. put_ch0x(v, c)
  2106.     SCREEN *v;
  2107.     int c;
  2108. {
  2109.     (*v->v.t.state)(v, c & 0x00ff);
  2110. }
  2111.  
  2112. static long ARGS_ON_STACK screen_open    P_((FILEPTR *f));
  2113. static long ARGS_ON_STACK screen_read    P_((FILEPTR *f, char *buf, long nbytes));
  2114. static long ARGS_ON_STACK screen_write P_((FILEPTR *f, const char *buf, long nbytes));
  2115. static long ARGS_ON_STACK screen_lseek P_((FILEPTR *f, long where, int whence));
  2116. static long ARGS_ON_STACK screen_ioctl P_((FILEPTR *f, int mode, void *buf));
  2117. static long ARGS_ON_STACK screen_close P_((FILEPTR *f, int pid));
  2118. static long ARGS_ON_STACK screen_select P_((FILEPTR *f, long p, int mode));
  2119. static void ARGS_ON_STACK screen_unselect P_((FILEPTR *f, long p, int mode));
  2120.  
  2121. static long ARGS_ON_STACK screen_datime    P_((FILEPTR *f, short *time, int rwflag));
  2122.  
  2123. DEVDRV vcon_device = {
  2124.     screen_open, screen_write, screen_read, screen_lseek, screen_ioctl,
  2125.     screen_datime, screen_close, screen_select, screen_unselect
  2126. };
  2127.  
  2128. static long ARGS_ON_STACK 
  2129. screen_open(f)
  2130.     FILEPTR *f;
  2131. {
  2132.     int fd, vt = f->fc.aux;
  2133.     char name[] = "u:\\pipe\\q$vt00";
  2134.  
  2135.     if (!rowoff) {
  2136.         init();
  2137.     } else if (!ttys[0].use_cnt || leaving)
  2138.         /* if we're init'ed already and vt00 is closed that means
  2139.            we're uninistalling... */
  2140.         return -EACCESS;
  2141.     if (!((struct tty *)f->devinfo)->use_cnt) {
  2142.         SCREEN *v = VT_SCREEN(vt);
  2143.  
  2144.         /* init and alloc screen memory if necessary */
  2145.         if (vt) {
  2146.             if (!v->v.t.vbase) {
  2147.                 char *vbase = (char *)kmalloc(scrnsize);
  2148.                 if (!vbase)
  2149.                     return -ENOMEM;
  2150.                 init_screen (v, vbase, v->v.t.rowlist, 0);
  2151.             } else if (v->v.t.on == V_FREE)
  2152.                 v->v.t.on = V_USED;
  2153.         }
  2154.         /* is there a better way??? */
  2155.         name[sizeof "u:\\pipe\\q$vt0"-1] = vt+'0';
  2156.         if ((fd = FOPEN (name, O_RDONLY|O_GLOBAL)) < 0)
  2157.             return fd;
  2158.         qfd[vt] = fd;
  2159.         q_fl[vt] = 0;
  2160.     }
  2161.  
  2162.     f->flags |= O_TTY;
  2163.     return 0;
  2164. }
  2165.  
  2166. static long ARGS_ON_STACK 
  2167. screen_close(f, pid)
  2168.     FILEPTR *f;
  2169.     int pid;
  2170. {
  2171.     UNUSED(pid);
  2172.  
  2173.     if (!((struct tty *)f->devinfo)->use_cnt) {
  2174.         int vt = f->fc.aux;
  2175.  
  2176.         /* close pipe */
  2177.         FCLOSE (qfd[vt]);
  2178.  
  2179.         /* last close on vt00 means uninstall... */
  2180.         if (!vt)
  2181.             deinit();
  2182.         /* otherwise it means free screen memory */
  2183.         else {
  2184.             SCREEN *v = VT_SCREEN(vt);
  2185.  
  2186.             if (v->v.t.on)
  2187.                 v->v.t.on = V_FREE;
  2188.             else {
  2189.                 kfree (v->v.t.vbase);
  2190.                 v->v.t.vbase = 0;
  2191.             }
  2192.         }
  2193.     }
  2194.     return 0;
  2195. }
  2196.  
  2197. static long ARGS_ON_STACK 
  2198. screen_write(f, buf, bytes)
  2199.     FILEPTR *f; const char *buf; long bytes;
  2200. {
  2201.     int vt = f->fc.aux;
  2202.     SCREEN *v = VT_SCREEN(vt);
  2203.     long *r;
  2204.     long ret = 0;
  2205.     int c;
  2206.     long tick;
  2207.  
  2208.     UNUSED(f);
  2209.  
  2210.     /* tty_write is calling us with no more than one line or 128
  2211.        chars at a time but still never(?) allows task-switches
  2212.        while doing a longer write... checkkeys() does this when
  2213.        it detects a keyboard interrupt but we cant call that.
  2214.        instead we look for 0->1 (_hz_200 & 3) ticks that happened
  2215.        while we were writing (there are 50 of them in a second)
  2216.        and yield() when found one.  (comments?)
  2217.     */
  2218. #if 0
  2219.     (void)checkkeys();
  2220. #else
  2221.     tick = _hz_200;
  2222. #endif
  2223.     v->hidecnt++;
  2224.     v->flags |= CURS_UPD;        /* for TOS 1.0 */
  2225.     curs_off(v);
  2226.     r = (long *)buf;
  2227.     if (vt) {
  2228.         while (bytes > 0) {
  2229.             c = (int) *r++;
  2230.             put_ch0x(v, c);
  2231.             bytes -= 4; ret+= 4;
  2232.         }
  2233.     } else {
  2234.         while (bytes > 0) {
  2235.             c = (int) *r++;
  2236.             put_ch00(v, c);
  2237.             bytes -= 4; ret+= 4;
  2238.         }
  2239.     }
  2240.     if (v->hidecnt > 0)
  2241.         --v->hidecnt;
  2242.     else
  2243.         v->hidecnt = 0;
  2244.     curs_on(v);
  2245.     v->flags &= ~CURS_UPD;
  2246. #if 1
  2247.     if (tick != _hz_200 && !(tick & 3))
  2248.         yield();
  2249. #endif
  2250.     return ret;
  2251. }
  2252.  
  2253. static long ARGS_ON_STACK 
  2254. screen_read(f, buf, bytes)
  2255.     FILEPTR *f; char *buf; long bytes;
  2256. {
  2257.     int vt = f->fc.aux;
  2258.  
  2259.     if ((f->flags & O_NDELAY) != q_fl[vt])
  2260.         FCNTL (qfd[vt], (long)(q_fl[vt] = f->flags&O_NDELAY), F_SETFL);
  2261.     return FREAD (qfd[vt], bytes, buf);
  2262. }
  2263.  
  2264. static long ARGS_ON_STACK 
  2265. screen_lseek(f, where, whence)
  2266.     FILEPTR *f;
  2267.     long where;
  2268.     int whence;
  2269. {
  2270. /* terminals always are at position 0 */
  2271.     UNUSED(f); UNUSED(where);
  2272.     UNUSED(whence);
  2273.     return 0;
  2274. }
  2275.  
  2276. static long ARGS_ON_STACK 
  2277. screen_ioctl(f, mode, buf)
  2278.     FILEPTR *f; int mode; void *buf;
  2279. {
  2280.     int vt = f->fc.aux;
  2281.     long *r = (long *)buf;
  2282.     struct winsize *w;
  2283.  
  2284.     UNUSED(f);
  2285.  
  2286.     if (mode == FIONREAD) {
  2287.         *r = FINSTAT (qfd[vt]);
  2288.         if (*r > 0)
  2289.             *r >>= 2;
  2290.     }
  2291.     else if (mode == FIONWRITE) {
  2292.         *r = 0x400;
  2293.     }
  2294.     else if (mode == TIOCFLUSH) {
  2295.         return FCNTL (qfd[vt], r, TIOCFLUSH);
  2296.     }
  2297.     else if (mode == TIOCGWINSZ) {
  2298.         SCREEN *v = VT_SCREEN(vt);
  2299.         w = (struct winsize *)buf;
  2300.         w->ws_row = v->maxy+1;
  2301.         w->ws_col = v->maxx+1;
  2302.     }
  2303.     else if (mode >= TCURSOFF && mode <= TCURSGRATE) {
  2304.         SCREEN *v = VT_SCREEN(vt);
  2305.         switch(mode) {
  2306.         case TCURSOFF:
  2307.             curs_off(v);
  2308.             v->hidecnt++;
  2309.             v->flags &= ~CURS_ON;
  2310.             break;
  2311.         case TCURSON:
  2312.             v->flags |= CURS_ON;
  2313.             v->hidecnt = 0;
  2314.             curs_on(v);
  2315.             break;
  2316.         case TCURSBLINK:
  2317.             curs_off(v);
  2318.             v->flags |= CURS_FLASH;
  2319.             curs_on(v);
  2320.             break;
  2321.         case TCURSSTEADY:
  2322.             curs_off(v);
  2323.             v->flags &= ~CURS_FLASH;
  2324.             curs_on(v);
  2325.             break;
  2326.         case TCURSSRATE:
  2327.             v->period = *((short *)buf);
  2328.             break;
  2329.         case TCURSGRATE:
  2330.             return v->period;
  2331.         }
  2332.     } else
  2333.         return -EINVAL;
  2334.  
  2335.     return 0;
  2336. }
  2337.  
  2338. static long ARGS_ON_STACK 
  2339. screen_select(f, p, mode)
  2340.     FILEPTR *f; long p; int mode;
  2341. {
  2342.     struct tty *tty = (struct tty *)f->devinfo;
  2343.     int vt = f->fc.aux;
  2344.  
  2345.     if (mode == O_RDONLY) {
  2346.         if (FINSTAT (qfd[vt])) {
  2347.             return 1;
  2348.         }
  2349.         if (tty) {
  2350.         /* avoid collisions with other processes */
  2351.             if (!tty->rsel)
  2352.                 tty->rsel = p;
  2353.         }
  2354.         return 0;
  2355.     } else if (mode == O_WRONLY) {
  2356.         return 1;
  2357.     }
  2358.     /* default -- we don't know this mode, return 0 */
  2359.     return 0;
  2360. }
  2361.  
  2362. static void ARGS_ON_STACK 
  2363. screen_unselect(f, p, mode)
  2364.     FILEPTR *f;
  2365.     long p;
  2366.     int mode;
  2367. {
  2368.     struct tty *tty = (struct tty *)f->devinfo;
  2369.  
  2370.     if (tty) {
  2371.         if (mode == O_RDONLY && tty->rsel == p)
  2372.             tty->rsel = 0;
  2373.         else if (mode == O_WRONLY && tty->wsel == p)
  2374.             tty->wsel = 0;
  2375.     }
  2376. }
  2377.  
  2378. long ARGS_ON_STACK 
  2379. screen_datime(f, timeptr, rwflag)
  2380.     FILEPTR *f;
  2381.     short *timeptr;
  2382.     int rwflag;
  2383. {
  2384.     int vt = f->fc.aux;
  2385.  
  2386.     if (rwflag)
  2387.         return -EACCESS;
  2388.     return FDATIME (timeptr, qfd[vt], 0);
  2389. }
  2390. SHAR_EOF
  2391. cat << \SHAR_EOF > vcon.h
  2392. #if 1
  2393.  
  2394. #ifdef __GNUC__
  2395. #define EXITING volatile    /* function never returns */
  2396. #else
  2397. #define EXITING
  2398. #endif
  2399.  
  2400. /* define how to call functions with stack parameter passing */
  2401. #ifdef __TURBOC__
  2402. #define ARGS_ON_STACK cdecl
  2403. #else
  2404. #define ARGS_ON_STACK
  2405. #endif
  2406.  
  2407. /* define to indicate unused variables */
  2408. #ifdef __TURBOC__
  2409. #define UNUSED(x)    (void)x
  2410. #else
  2411. #define UNUSED(x)
  2412. #endif
  2413.  
  2414. #ifdef __STDC__
  2415. #define P_(x) x
  2416. #else
  2417. #define P_(x) ()
  2418. #define const
  2419. #define volatile
  2420. #endif
  2421.  
  2422. typedef unsigned short    ushort;
  2423. typedef long ARGS_ON_STACK (*Func)();
  2424. #include "file.h"
  2425. #else
  2426. #include "filesys.h"
  2427. #endif
  2428.  
  2429. #define CTRL(x) ((x) & 0x1f)
  2430. #ifndef T_NOFLSH
  2431. #define T_NOFLSH    0x0040        /* don't flush buffer when signals
  2432.                        are received */
  2433. #endif
  2434.  
  2435. #if !RAW
  2436. #undef RAW
  2437. #undef ECHO
  2438. #define RAW T_RAW
  2439. #define ECHO T_ECHO
  2440. #define CRMOD T_CRMOD
  2441. #define CBREAK T_CBREAK
  2442. #define TOSTOP T_TOSTOP
  2443. #define XKEY T_XKEY
  2444. #endif
  2445.  
  2446. extern struct kerinfo *kernel;
  2447. #define CCONWS (void)(*kernel->dos_tab[0x09])
  2448.  
  2449. #define FOPEN (*kernel->dos_tab[0x3d])
  2450. #define FCLOSE (*kernel->dos_tab[0x3e])
  2451. #define FREAD (*kernel->dos_tab[0x3f])
  2452. #define MXALLOC (*kernel->dos_tab[0x44])
  2453. #define FDATIME (*kernel->dos_tab[0x44])
  2454. #define FCNTL (*kernel->dos_tab[0x104])
  2455. #define FINSTAT (*kernel->dos_tab[0x105])
  2456. #define FGETCHAR (*kernel->dos_tab[0x107])
  2457.  
  2458. #define SPRINTF (*kernel->sprintf)
  2459. #define DEBUG (*kernel->debug)
  2460. #define ALERT (*kernel->alert)
  2461. #define TRACE (*kernel->trace)
  2462. #define FATAL (*kernel->fatal)
  2463. #define KMALLOC (*kernel->kmalloc)
  2464. #define KFREE (*kernel->kfree)
  2465. #define SLEEP (*kernel->sleep)
  2466. #define WAKESELECT (*kernel->wakeselect)
  2467.  
  2468. SHAR_EOF
  2469. cat << \SHAR_EOF > vtdev.h
  2470. /* should be equivalent... atleast for mintlib. */
  2471. #include <string.h>
  2472. #define quickmove memmove
  2473. #define zero bzero
  2474. /* only possible because main open()s /dev/vt00 that calls this. */
  2475. #define kcore(x) MXALLOC((long)(x),0)
  2476. /* should this do something? */
  2477. #define checkkeys() (0)
  2478. #define kmalloc KMALLOC
  2479. #define kfree KFREE
  2480. #define bconout Bconout
  2481. #define yield() SLEEP(1, 0l)
  2482.  
  2483. /* number of terminals (max) */
  2484. #define N_VT  10
  2485.  
  2486. #define MAX_PLANES 8
  2487.  
  2488. #define ALT_1 0x780000L
  2489. #define ALT_2 0x790000L
  2490. #define ALT_0 0x810000L
  2491.  
  2492. struct screen;
  2493.  
  2494. typedef void (*Vfunc) P_((struct screen *, int));
  2495.  
  2496. typedef struct screen {
  2497.     short    hidecnt;    /* cursor hide count */
  2498.     short    mcurx, mcury;    /* current mouse X, Y position */
  2499.     char    mdraw;
  2500.     char    mouseflag;
  2501.     long    junk1;
  2502.     short    savex, savey;    /* saved X, Y position */
  2503.     short    msavelen;    /* mouse save stuff */
  2504.     long    msaveaddr;
  2505.     short    msavestat;
  2506.     union {
  2507.         long    msavearea[64];
  2508. /* additional stuff, NOT for vt00! */
  2509.         struct {
  2510.             Vfunc    state;
  2511.             short    vescy1;
  2512.             int    fgmask[MAX_PLANES];
  2513.             int    bgmask[MAX_PLANES];
  2514.             char    *vbase;        /* screens address */
  2515.             char    *rowlist;    /* pointer to line offsets */
  2516.             short    on;        /* 0 if screen `stored'... */
  2517. #define V_USED    1    /* not stored, open */
  2518. #define V_FREE    2    /* not stored, closed, free screen memory later */
  2519.         } t;
  2520.     } v;
  2521.     long    user_tim, next_tim; /* time vector stuff */
  2522.     long    user_but, user_cur,
  2523.         user_mot;    /* more user vectors */
  2524.     short    cheight;    /* character height */
  2525.     short    maxx;        /* number of characters across - 1 */
  2526.     short    maxy;        /* number of characters high - 1 */
  2527.     short    linelen;    /* length (in bytes) of a line of characters */    
  2528.     short    bgcol;        /* background color */
  2529.     short    fgcol;        /* foreground color */
  2530.     char    *cursaddr;    /* cursor address */
  2531.     short    v_cur_of;    /* ??? */
  2532.     short    cx, cy;        /* current (x,y) position of cursor */
  2533.     char    period;        /* cursor flash period (in frames) */    
  2534.     char    curstimer;    /* cursor flash timer */
  2535.     char    *fontdata;    /* pointer to font data */
  2536.     short    firstcode;    /* first ASCII code in font */
  2537.     short    lastcode;    /* last ASCII code in font */
  2538.     short    form_width;    /* # bytes/scanline in font data */
  2539.     short    xpixel;
  2540.     char    *fontoff;    /* pointer to font offset table */
  2541.     char    flags;        /* e.g. cursor on/off */
  2542.     char    reserved;
  2543.     short    ypixel;
  2544.     short    width;        /* length of a screen scan line */
  2545.     short    planes;        /* number of planes on screen */
  2546.     short    planesiz;    /* length of a screen scan line */
  2547. } SCREEN;
  2548.  
  2549. #define SCNSIZE(v) ( (((long)v->maxy + hardscroll + 2)) * v->linelen )
  2550.  
  2551. /* possible flags for cursor state, etc. */
  2552. #define CURS_FLASH    0x01        /* cursor flashing */
  2553. #define CURS_FSTATE    0x02        /* cursor in flash state */
  2554. #define CURS_ON        0x04        /* cursor on */
  2555. #define FWRAP        0x08        /* wrap cursor at end of line */
  2556. #define FINVERSE    0x10        /* invert text */
  2557. #define FUNDERLINE    0x20        /* EXTENSION: underline text */
  2558. #define CURS_UPD    0x40        /* cursor update flag */
  2559.  
  2560. extern DEVDRV vcon_device;
  2561. extern struct tty ttys[];
  2562. extern struct dev_descr devinfo[];
  2563. extern int vcurrent;
  2564. extern short hardscroll, leaving;
  2565. extern SCREEN *v00, v0x[], *current;
  2566. int setcurrent();
  2567. SHAR_EOF
  2568. cat << \SHAR_EOF > Makefile
  2569. # Makefile for vcon; nothing special...
  2570.  
  2571. CC = gcc
  2572. CFLAGS = -g -mshort -O2 -Wall
  2573. LDFLAGS = -g -mshort
  2574.  
  2575. vcon: vcon.o vtdev.o
  2576.     $(CC) -G $(LDFLAGS) vcon.o vtdev.o -ovcon
  2577.     @echo done.
  2578.  
  2579. vcon.sym: vcon.o vtdev.o
  2580.     $(CC) -B/usr/lib/sym- $(LDFLAGS) vcon.o vtdev.o -ovcon.sym
  2581.     @echo done.
  2582.  
  2583. SHAR_EOF
  2584. #    End of shell archive
  2585. exit 0
  2586. -- 
  2587. J"urgen Lock / nox@jelal.north.de / UUCP: ..!uunet!unido!uniol!jelal!nox
  2588.                                 ...ohne Gewehr
  2589. PGP public key fingerprint =  8A 18 58 54 03 7B FC 12  1F 8B 63 C7 19 27 CF DA 
  2590.